#include "oled.h"
#include "font.h"

//IO26:OLED_SCL    IO25:OLED_SDA

unsigned char OLED_GRAM[144][4];

void OLED_Init(void)
{
    //OLED_SCL OLED_SDA
    pinMode(26,OUTPUT);
    pinMode(25,OUTPUT);
    OLED_SCL_H;
    OLED_SDA_H;

    delay(10);
    
    OLED_Write_Cmd_Data(0xae,OLED_CMD); /*display off*/
    OLED_Write_Cmd_Data(0x00,OLED_CMD); /*set lower column address*/
    OLED_Write_Cmd_Data(0x10,OLED_CMD); /*set higher column address*/
    OLED_Write_Cmd_Data(0x00,OLED_CMD); /*set display start line*/
    OLED_Write_Cmd_Data(0xb0,OLED_CMD); /*set page address*/
    OLED_Write_Cmd_Data(0x81,OLED_CMD); /*contract control*/
    OLED_Write_Cmd_Data(0xff,OLED_CMD); /*128*/
    OLED_Write_Cmd_Data(0xa1,OLED_CMD); /*set segment remap*/
    OLED_Write_Cmd_Data(0xa6,OLED_CMD); /*normal / reverse*/
    OLED_Write_Cmd_Data(0xa8,OLED_CMD); /*multiplex ratio*/
    OLED_Write_Cmd_Data(0x1f,OLED_CMD); /*duty = 1/32*/
    OLED_Write_Cmd_Data(0xc8,OLED_CMD); /*Com scan direction*/
    OLED_Write_Cmd_Data(0xd3,OLED_CMD); /*set display offset*/
    OLED_Write_Cmd_Data(0x00,OLED_CMD);
    OLED_Write_Cmd_Data(0xd5,OLED_CMD); /*set osc division*/
    OLED_Write_Cmd_Data(0x80,OLED_CMD);
    OLED_Write_Cmd_Data(0xd9,OLED_CMD); /*set pre-charge period*/
    OLED_Write_Cmd_Data(0x1f,OLED_CMD);
    OLED_Write_Cmd_Data(0xda,OLED_CMD); /*set COM pins*/
    OLED_Write_Cmd_Data(0x00,OLED_CMD);
    OLED_Write_Cmd_Data(0xdb,OLED_CMD); /*set vcomh*/
    OLED_Write_Cmd_Data(0x40,OLED_CMD);
    OLED_Write_Cmd_Data(0x8d,OLED_CMD); /*set charge pump enable*/
    OLED_Write_Cmd_Data(0x14,OLED_CMD);
    OLED_Clear();
    OLED_Write_Cmd_Data(0xaf,OLED_CMD); /*display ON*/
}

void OLED_IIC_Start(void)
{
    OLED_SDA_H;
    OLED_SCL_H;delayMicroseconds(5);
    OLED_SDA_L;delayMicroseconds(5);
    OLED_SCL_L;delayMicroseconds(5);
}

void OLED_IIC_Stop(void)
{
    OLED_SDA_L;delayMicroseconds(5);
    OLED_SCL_H;delayMicroseconds(5);
    OLED_SDA_H;delayMicroseconds(5);
}

void OLED_IIC_WaitAck(void)
{
    OLED_SDA_H;delayMicroseconds(5);
    OLED_SCL_H;delayMicroseconds(5);
    OLED_SCL_L;delayMicroseconds(5);
}

//写入一个字节
void OLED_Send_Byte(unsigned char data)
{
    unsigned char i;
    for(i = 0; i < 8; i ++)
    {
        if(data & 0x80)
        {
            OLED_SDA_H;
        }
        else
        {
            OLED_SDA_L;
        }
        delayMicroseconds(5);
        
        OLED_SCL_H;delayMicroseconds(5);
        OLED_SCL_L;
        
        data <<= 1;
        
        delayMicroseconds(5);
    }
}

//发送一个字节；mode：数据/命令标志，0表示命令，1表示数据
void OLED_Write_Cmd_Data(unsigned char data,unsigned char mode)
{
    OLED_IIC_Start();
    OLED_Send_Byte(OLED_Addr);
    OLED_IIC_WaitAck();
    if(mode)
        OLED_Send_Byte(0x40);
    else OLED_Send_Byte(0x00);
    OLED_IIC_WaitAck();
    OLED_Send_Byte(data);
    OLED_IIC_WaitAck();
    OLED_IIC_Stop();
}

void OLED_DisPlay_ON(void)
{
    OLED_Write_Cmd_Data(0x8d,OLED_CMD);
    OLED_Write_Cmd_Data(0x14,OLED_CMD);
    OLED_Write_Cmd_Data(0xaf,OLED_CMD);
}

void OLED_DisPlay_OFF(void)
{
    OLED_Write_Cmd_Data(0x8d,OLED_CMD);
    OLED_Write_Cmd_Data(0x10,OLED_CMD);
    OLED_Write_Cmd_Data(0xae,OLED_CMD);
}

void OLED_Refresh(void)
{
    unsigned char i,j;
    for(i = 0; i < 4; i ++)
    {
        OLED_Write_Cmd_Data(0xb0 + i,OLED_CMD);
        OLED_Write_Cmd_Data(0x00,OLED_CMD);
        OLED_Write_Cmd_Data(0x10,OLED_CMD);
        OLED_IIC_Start();
        OLED_Send_Byte(0x78);
        OLED_IIC_WaitAck();
        OLED_Send_Byte(0x40);
        OLED_IIC_WaitAck();
        for(j = 0; j < 128; j ++)
        {
            OLED_Send_Byte(OLED_GRAM[j][i]);
            OLED_IIC_WaitAck();
        }
        OLED_IIC_Stop();
    }
}

void OLED_Clear(void)
{
    unsigned char i,j;
    for(i = 0; i < 4; i ++)
    {
       for(j = 0; j < 128; j ++)
            OLED_GRAM[j][i] = 0;
    }
    OLED_Refresh();
}

void OLED_ColorInv(unsigned char i)
{
    if(i == 0)
        OLED_Write_Cmd_Data(0xa6,OLED_CMD);
    if(i == 1)
        OLED_Write_Cmd_Data(0xa7,OLED_CMD);
}

void OLED_Display_UpDown(unsigned char i)
{
    if(i == 0)
    {
        OLED_Write_Cmd_Data(0xc8,OLED_CMD);
        OLED_Write_Cmd_Data(0xa1,OLED_CMD);
    }
    if(i == 1)
    {
        OLED_Write_Cmd_Data(0xc0,OLED_CMD);
        OLED_Write_Cmd_Data(0xa0,OLED_CMD);
    }
}

void OLED_DrawPoint(unsigned char x,unsigned char y,unsigned char t)
{
    unsigned char i,m,n;
    i = y / 8;
    m = y % 8;
    n = 1 << m;
    if(t)
        OLED_GRAM[x][i] |= n;
    else
    {
        OLED_GRAM[x][i] = ~OLED_GRAM[x][i];
        OLED_GRAM[x][i] |= n;
        OLED_GRAM[x][i] = ~OLED_GRAM[x][i];
    }
}

void OLED_DrawLine(unsigned char x1,unsigned char y1,unsigned char x2,unsigned char y2,unsigned char mode)
{
    int t; 
    int xerr = 0,yerr = 0,delta_x,delta_y,distance;
    int incx,incy,uRow,uCol;
    delta_x = x2 - x1;
    delta_y = y2 - y1;
    uRow = x1;
    uCol = y1;
    if(delta_x > 0)
        incx = 1;
    else if (delta_x == 0)
        incx = 0;
    else
    {
        incx = -1;
        delta_x = -delta_x;
    }
    if(delta_y > 0)
        incy = 1;
    else if (delta_y == 0)
        incy = 0;
    else
    {
        incy = -1;
        delta_y = -delta_x;
    }
    if(delta_x > delta_y)
        distance = delta_x;
    else 
        distance = delta_y;
    for(t = 0; t < distance + 1; t ++)
    {
        OLED_DrawPoint(uRow,uCol,mode);
        xerr += delta_x;
        yerr += delta_y;
        if(xerr > distance)
        {
            xerr -= distance;
            uRow += incx;
        }
        if(yerr > distance)
        {
            yerr -= distance;
            uCol += incy;
        }
    }
}

void OLED_DrawCircle(unsigned char x,unsigned char y,unsigned char r)
{
    int a,b,num;
    a = 0;
    b = r;
    while(2 * b * b >= r * r)      
    {
        OLED_DrawPoint(x + a, y - b,1);
        OLED_DrawPoint(x - a, y - b,1);
        OLED_DrawPoint(x - a, y + b,1);
        OLED_DrawPoint(x + a, y + b,1);
 
        OLED_DrawPoint(x + b, y + a,1);
        OLED_DrawPoint(x + b, y - a,1);
        OLED_DrawPoint(x - b, y - a,1);
        OLED_DrawPoint(x - b, y + a,1);
        
        a ++;
        num = (a * a + b * b) - r * r;
        if(num > 0)
        {
            b --;
            a --;
        }
    }
}

void OLED_ShowChar(unsigned char x,unsigned char y,unsigned char chr,unsigned char size1,unsigned char mode)
{
    unsigned char i,m,temp,size2,chr1;
    unsigned char x0 = x,y0 = y;
    if(size1 == 8)
        size2 = 6;
    else
        size2 = (size1 / 8 + ((size1 % 8) ? 1 : 0)) * (size1 / 2);
    chr1 = chr - ' ';
    for(i = 0; i < size2; i ++)
    {
        if(size1 == 8)
            temp = asc2_0806[chr1][i];
        else if(size1 == 12)
            temp = asc2_1206[chr1][i];
        else if(size1 == 16)
            temp = asc2_1608[chr1][i];
        else if(size1 == 24)
            temp=asc2_2412[chr1][i];
        else return;
        for(m = 0; m < 8; m ++)
        {
            if(temp & 0x01)
                OLED_DrawPoint(x,y,mode);
            else
                OLED_DrawPoint(x,y,!mode);
            temp >>= 1;
            y ++;
        }
        x ++;
        if((size1 != 8) && ((x - x0) == size1 / 2))
        {
            x = x0;
            y0 += 8;
        }
        y=y0;
    }
}

void OLED_ShowString(unsigned char x,unsigned char y,unsigned char *chr,unsigned char size1,unsigned char mode)
{
    while((*chr >= ' ') && (*chr <= '~'))
    {
        OLED_ShowChar(x,y,*chr,size1,mode);
        if(size1 == 8)
            x += 6;
        else
            x+=size1 / 2;
        chr ++;
    }
}

long OLED_Pow(unsigned char m,unsigned char n)
{
    long result = 1;
    while(n --)
    {
      result *= m;
    }
    return result;
}

void OLED_ShowNum(unsigned char x,unsigned char y,int num,unsigned char len,unsigned char size1,unsigned char mode)
{
    unsigned char t,temp,m = 0;
    if(size1 == 8)
        m = 2;
    for(t = 0; t< len; t ++)
    {
        temp = (num / OLED_Pow(10,len - t - 1)) % 10;
            if(temp == 0)
                OLED_ShowChar(x + (size1 / 2 + m)*t,y,'0',size1,mode);
            else OLED_ShowChar(x + (size1 / 2 + m)*t,y,temp + '0',size1,mode);
    }
}

void OLED_ShowChinese(unsigned char x,unsigned char y,unsigned char num,unsigned char size1,unsigned char mode)
{
    unsigned char m,temp;
    unsigned char x0 = x,y0 = y;
    int i,size3 = (size1 / 8 + ((size1 % 8) ? 1 : 0)) * size1;
    for(i = 0; i < size3; i ++)
    {
        if(size1 == 16)
            temp = Hzk1[num][i];
        else if(size1 == 24)
            temp = Hzk2[num][i];
        else if(size1 == 32)       
            temp=Hzk3[num][i];
        else if(size1 == 64)
            temp = Hzk4[num][i];
        else return;
        for(m = 0; m < 8; m ++)
        {
            if(temp & 0x01)
                OLED_DrawPoint(x,y,mode);
            else
                OLED_DrawPoint(x,y,!mode);
            temp >>= 1;
            y ++;
        }
        x ++;
        if((x - x0) == size1)
        {
            x = x0;
            y0 += 8;
        }
        y = y0;
    }
}

void OLED_ScrollDisplay(unsigned char num,unsigned char space,unsigned char mode)
{
    unsigned char i,n,t = 0,m = 0,r;
    while(1)
    {
        if(m == 0)
        {
            OLED_ShowChinese(128,8,t,16,mode);
            t++;
        }
        if(t == num)
        {
            for(r = 0; r < 16 * space; r ++)
             {
                for(i = 1; i < 144; i ++)
                    {
                        for(n = 0; n < 4; n ++)
                            OLED_GRAM[i - 1][n]=OLED_GRAM[i][n];
                    }
                OLED_Refresh();
             }
        t=0;
        }
        m++;
        if(m == 16)
            m = 0;
        for(i = 1; i < 144; i ++)
        {
            for(n = 0; n < 4; n ++)
                OLED_GRAM[i - 1][n]=OLED_GRAM[i][n];
        }
        OLED_Refresh();
    }
}

void OLED_ShowPicture(unsigned char x,unsigned char y,unsigned char sizex,unsigned char sizey,unsigned char BMP[],unsigned char mode)
{
    int j = 0;
    unsigned char i,n,temp,m;
    unsigned char x0 = x,y0 = y;
    sizey = sizey / 8 + ((sizey % 8) ? 1 : 0);
    for(n = 0; n < sizey; n ++)
    {
         for(i = 0; i < sizex; i ++)
         {
            temp = BMP[j];
            j ++;
            for(m = 0; m < 8; m ++)
            {
                if(temp & 0x01)OLED_DrawPoint(x,y,mode);
                else OLED_DrawPoint(x,y,!mode);
                temp >>= 1;
                y ++;
            }
            x ++;
            if((x - x0) == sizex)
            {
                x = x0;
                y0 += 8;
            }
            y = y0;
        }
    }
}
